﻿// © Benn Eichhorn 2010
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Algobox.Feeds.Finance.Bats.PitchClient.Messages
{
    /// <summary>
    /// Singleton Bats Order Execution message
    /// </summary>
    public class OrderExecution : IMessage
    {
        private OrderExecution() { }

        private static OrderExecution _instance = new OrderExecution();

        /// <summary>
        /// Get's the singleton instance of the OrderExecution class
        /// </summary>
        /// <returns>Current OrderExecution</returns>
        public static OrderExecution GetInstance() { return _instance; }

        public char MessageType { get { return 'E'; } }

        /// <summary>
        /// Milliseconds since midnight
        /// </summary>
        public int TimeStampMillis;

        /// <summary>
        /// Slow, calculates current TimeStamp from TimeStampMillis
        /// </summary>
        public DateTime TimeStamp { get { return BatsMessageParser.Date.AddMilliseconds(TimeStampMillis); } }

        /// <summary>
        /// Day unique order reference
        /// </summary>
        public string OrderReference;

        /// <summary>
        /// The day unique trade reference
        /// </summary>
        public string TradeReference;

        /// <summary>
        /// The number of shares executed on this trade
        /// </summary>
        public ulong ExecutedShares;


        public override string ToString()
        {
            return String.Format("IMessage->OrderExec: OrderReference={0},TradeReference={1},ExecutedShares={2},TimeStamp={3}", OrderReference, TradeReference, ExecutedShares, TimeStamp);
        }


        // Order Execution
        const int S_E_ORDERREF_LOC = 10;
        const int S_E_ORDERREF_LEN = 12;
        const int S_E_SHARES_LOC = 22;
        const int S_E_SHARES_LEN = 6;
        const int S_E_TRADEREF_LOC = 28;
        const int S_E_TRADEREF_LEN = 12;

        // Order Execution Long
        const int S_e_ORDERREF_LOC = 10;
        const int S_e_ORDERREF_LEN = 12;
        const int S_e_SHARES_LOC = 22;
        const int S_e_SHARES_LEN = 10;
        const int S_e_TRADEREF_LOC = 32;
        const int S_e_TRADEREF_LEN = 12;
        
        internal static IMessage ParseShort(ref string inbound)
        {
            // get sequenced data message timestamp
            if (!Int32.TryParse(inbound.Substring(BatsMessageParser.S_TIMESTAMP_LOC, BatsMessageParser.S_TIMESTAMP_LEN), out _instance.TimeStampMillis))
            {
                Messages.Error message = Messages.Error.GetInstance("Sequenced data message failed to parse TimeStamp millis as Double", ref inbound);
                return message;
            }
            if (!UInt64.TryParse(inbound.Substring(S_E_SHARES_LOC, S_E_SHARES_LEN), out _instance.ExecutedShares))
            {
                return Messages.Error.GetInstance("OrderExecution failed to parse ExecutedShares as Int64", ref inbound);
            }

            _instance.OrderReference = inbound.Substring(S_E_ORDERREF_LOC, S_E_ORDERREF_LEN);
            _instance.TradeReference = inbound.Substring(S_E_TRADEREF_LOC, S_E_TRADEREF_LEN);

            return _instance;
        } 


        internal static IMessage ParseLong(ref string inbound)
        {
            // get sequenced data message timestamp
            if (!Int32.TryParse(inbound.Substring(BatsMessageParser.S_TIMESTAMP_LOC, BatsMessageParser.S_TIMESTAMP_LEN), out _instance.TimeStampMillis))
            {
                Messages.Error message = Messages.Error.GetInstance("Sequenced data message failed to parse TimeStamp millis as Double", ref inbound);
                return message;
            }
            if (!UInt64.TryParse(inbound.Substring(S_e_SHARES_LOC, S_e_SHARES_LEN), out _instance.ExecutedShares))
            {
                return Messages.Error.GetInstance("OrderExecution failed to parse ExecutedShares as Int64", ref inbound);
            }

            _instance.OrderReference = inbound.Substring(S_e_ORDERREF_LOC, S_e_ORDERREF_LEN);
            _instance.TradeReference = inbound.Substring(S_e_TRADEREF_LOC, S_e_TRADEREF_LEN);

            return _instance;
        }


        /// <summary>
        /// Deep clone
        /// </summary>
        /// <returns></returns>
        public OrderExecution Clone()
        {
            OrderExecution clone = new OrderExecution();
            clone.ExecutedShares = _instance.ExecutedShares;
            clone.OrderReference = _instance.OrderReference;
            clone.TimeStampMillis = _instance.TimeStampMillis;
            clone.TradeReference = _instance.TradeReference;
            return clone;
        }
    }
}
